<?php

namespace App\Http\Services\CoolNumberShoppingMall;

use App\Exceptions\ErrorCodeException;
use App\Exceptions\PublicException;
use App\Http\Model\CoolNumberShoppingMall\CoolNumber;
use App\Http\Model\CoolNumberShoppingMall\Order;
use App\Http\Model\CoolNumberShoppingMall\OrderLog;
use App\Http\Model\CoolNumberShoppingMall\ShoppingMallGoods;
use App\Http\Model\CoolNumberShoppingMall\UseLog;
use App\Http\Model\CoolNumberShoppingMall\UserUseLog;
use App\Http\Model\Hint;
use App\Http\Model\User;
use App\Http\Services\CommonPrivateMsgServices;
use App\Http\Services\CommonServices;
use App\Http\Services\CommonSystemMsgServices;
use App\Http\Services\UserServices;
use App\Http\Traits\DelayTask;
use Illuminate\Support\Facades\DB;

class ShoppingMallOrderServices extends CommonServices
{
    use DelayTask;

    /**
     * @var Order
     */
    private $modelOrder;

    /**
     * @var ShoppingMallGoods
     */
    private $modelGoods;

    /**
     * @var User
     */
    private $modelUser;

    /**
     * @var UseLog
     */
    private $modelUseLog;

    /**
     * @var UserUseLog
     */
    private $modelUserUseLog;

    /**
     * @var CoolNumber
     */
    private $modelCoolNumber;

    /**
     * @var OrderLog
     */
    private $modelOrderLog;

    /**
     * @var UserServices
     */
    private $serviceUser;

    /**
     * @var CoolNumberServices
     */
    private $serviceCoolNumber;

    /**
     * @var ShoppingMallGoodsServices
     */
    private $serviceGoods;

    /**
     * @var CommonPrivateMsgServices
     */
    private $servicePrivateMsg;

    /**
     * @var CommonSystemMsgServices
     */
    private $serviceSystemMsg;

    /**
     * 构造函数
     */
    public function __construct()
    {
        parent::__construct();
        $this->modelGoods = new ShoppingMallGoods();
        $this->modelOrder = new Order();
        $this->modelUser = new User();
        $this->modelUseLog = new UseLog();
        $this->modelUserUseLog = new UserUseLog();
        $this->modelCoolNumber = new CoolNumber();
        $this->modelOrderLog = new OrderLog();
        $this->serviceUser = new UserServices();
        $this->serviceCoolNumber = new CoolNumberServices();
        $this->serviceGoods = new ShoppingMallGoodsServices();
        $this->servicePrivateMsg = new CommonPrivateMsgServices();
        $this->serviceSystemMsg = new CommonSystemMsgServices();
    }

    /**
     * 获取用户购买的所有靓号
     *
     * Created at 2021/12/8 14:43
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $userId
     * @return array
     */
    public function getAllOrder(int $userId): array
    {
        $list = [];
        $allOrder = $this->modelOrder->getSingle(['user_id' => $userId, 'is_show' => Order::IS_SHOW_YES],
            ['id', 'goods_id', 'uuid', 'created_at', 'expiry_time']);
        if (!$allOrder) {
            return $list;
        }

        $goodIds = array_column($allOrder, 'goods_id');
        $where[] = [
            function ($query) use ($goodIds) {
                $query->whereIn('id', $goodIds);
            },
        ];
        $goods = collect($this->modelGoods->getSingle($where, ['id', 'goods_name', 'goods_image', 'get_description']))
            ->keyBy('id')->toArray();
        foreach ($allOrder as $item) {
            $goodsId = $item['goods_id'];
            $list[] = [
                'user_pack_id' => $item['id'],
                'user_id' => $userId,
                'prop_id' => 0,
                'num' => 1,
                'created_at' => $item['created_at'],
                'name' => $goods[$goodsId]['goods_name'] ?? '',
                'msg' => $goods[$goodsId]['get_description'] ?? '',
                'data_image' => getFullImageUrl($goods[$goodsId]['goods_image'] ?? ''),
                'give_type' => 0,
                'is_present' => 1,
                'select_type' => 0,
                'has_select' => 1,
                'has_search' => 0,
                'type' => 'cool_number',
                'expiry_time' => $item['expiry_time'],
            ];
        }

        return $list;
    }

    /**
     * 检查订单
     *
     * Created at 2021/12/8 17:05
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $orderId
     * @return array
     * @throws PublicException
     */
    private function checkOrder(int $orderId): array
    {
        $order = $this->modelOrder->getSingle(['id' => $orderId], ['user_id', 'goods_id', 'uuid', 'expiry_time'], true);
        if (!$order) {
            throw new PublicException('数据记录不存在');
        }

        if ($order['expiry_time'] <= time()) {
            throw new PublicException('已失效，不能使用');
        }

        $query = $this->modelUser->getTotalNumberOfQueryRaw('uuid="' . $order['uuid'] . '"');
        if ($query) {// 已被人使用
            throw new PublicException('靓号已被使用');
        }

        return $order;
    }

    /**
     * 使用靓号
     *
     * Created at 2021/12/8 16:38
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $orderId
     * @throws PublicException|\Throwable
     */
    public function useCoolNumber(int $orderId)
    {
        $order = $this->checkOrder($orderId);
        DB::beginTransaction();
        try {
            $this->addUuidUseLog($order['user_id'], $order['uuid'], $order['expiry_time']);// 添加靓号使用记录
            $this->addUuidUserUseLog($order['user_id'], $order['uuid'], $order['expiry_time'], UserUseLog::CHANGE_AUTO);// 添加用户使用靓号记录
            $this->updateCoolNumberStatus($order['uuid'], $order['expiry_time']);// 更新靓号使用状态
            $this->modelOrder->singleUpdate(['id' => $orderId], ['is_show' => Order::IS_SHOW_NO, 'updated_at' => time()]);// 隐藏
            $this->serviceUser->setUid($order['user_id'], $order['uuid']);// 更换用户UUID
            $this->serviceUser->setLiang($order['user_id'], 1);// 打上靓号标记
            DB::commit();
        } catch (\Throwable $exception) {
            DB::rollBack();
            throw $exception;
        }
    }

    /**
     * Created at 2021/12/8 16:31
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $userId
     * @param string $newUuid
     * @param int $expiryTime
     */
    private function addUuidUseLog(int $userId, string $newUuid, int $expiryTime)
    {
        $where['user_id'] = $userId;
        $where[] = ['expiry_time', '>', time()];
        $query = $this->modelUseLog->getSingle($where, ['id', 'uuid'], true);
        if ($query) {
            $this->modelUseLog->singleUpdate(['id' => $query['id']], ['expiry_time' => time(), 'updated_at' => time()]); //用户有正在使用的靓号
            $this->modelCoolNumber->singleUpdateRaw('uuid="' . $query['uuid'] . '"', ['is_use' => CoolNumber::IS_USE_NO, 'expiry_time' => time()]);
        }

        $this->modelUseLog->insertSingle(['uuid' => $newUuid, 'user_id' => $userId,
            'expiry_time' => $expiryTime, 'created_at' => time(), 'updated_at' => time()]);// 记录UUID使用日志
    }

    /**
     * Created at 2021/12/8 16:32
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $userId
     * @param string $newUuid
     * @param int $expiryTime
     * @param int $changeMode
     * @param int $operatorUserId
     * @param string $operatorUser
     */
    private function addUuidUserUseLog(int $userId, string $newUuid, int $expiryTime, int $changeMode, int $operatorUserId = 0, string $operatorUser = '')
    {
        $where['user_id'] = $userId;
        $where[] = ['expiry_time', '>', time()];
        $query = $this->modelUserUseLog->getSingle($where, ['id'], true);
        if ($query) {
            $this->modelUserUseLog->singleUpdate(['id' => $query['id']], ['expiry_time' => time()]); //用户有正在使用的靓号
        }

        // 获取用户当前uuid
        $userCurrentUuid = $this->modelUser->getSingleValue(['user_id' => $userId], 'uuid');
        $this->modelUserUseLog->insertSingle(['old_uuid' => $userCurrentUuid, 'new_uuid' => $newUuid,
            'user_id' => $userId, 'expiry_time' => $expiryTime, 'operator_user_id' => $operatorUserId, 'operator_user' => $operatorUser,
            'change_mode' => $changeMode, 'created_at' => time(), 'updated_at' => time()]);
    }

    /**
     * Created at 2021/12/8 16:33
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param string $newUuid
     * @param int $expiryTime
     * @throws PublicException
     */
    private function updateCoolNumberStatus(string $newUuid, int $expiryTime)
    {
        $query = $this->modelCoolNumber->getTotalNumberOfQueryRaw('uuid="' . $newUuid . '"');
        if (!$query) {
            return;
        }

        $affectRow = $this->serviceCoolNumber->beginUseUuid($newUuid, $expiryTime);
        if (!$affectRow) {
            throw new PublicException('靓号已被使用');
        }

        $this->modelCoolNumber->incUsageTimes($newUuid);// 更新靓号使用次数
    }

    /**
     * 赠送靓号(道具背包)
     *
     * Created at 2021/12/8 17:19
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $orderId
     * @param int $toUserId
     * @throws PublicException
     */
    public function presentCoolNumber(int $orderId, int $toUserId)
    {
        $order = $this->checkOrder($orderId);
        $orderUserId = $order['user_id'];
        $toUser = $this->modelUser->get_user($toUserId);
        if (!$toUser) {
            throw new PublicException('要赠送的用户不存在');
        }

        DB::beginTransaction();
        $this->modelOrder->singleRemove(['id' => $orderId]);
        unset($order['id']);
        $this->modelOrder->insertSingle(array_merge($order, [
            'user_id' => $toUserId,
            'is_show' => $order['expiry_time'] > time() ? Order::IS_SHOW_YES : Order::IS_SHOW_NO,
            'updated_at' => time(),
        ]));
        $this->modelOrderLog->insertSingle(array_merge($order, [
            'user_id' => $toUserId,
            'giver_user_id' => $orderUserId,
            'created_at' => time(),
            'updated_at' => time(),
        ]));
        DB::commit();
        $this->serviceGoods->sendMessage($orderUserId, $toUserId, $this->modelGoods->getSingle(['id' => $order['goods_id']], ['*'], true));
    }

    /**
     * 靓号过期
     *
     * Created at 2021/12/8 19:27
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param string $uuid
     */
    public function delayedCallback(string $uuid)
    {
        DB::beginTransaction();
        $listOrder = $this->modelOrder->getListRaw('uuid="' . $uuid . '" and expiry_time>0 and expiry_time<=' . time(), ['id', 'user_id']);
        if ($listOrder) {// 删除过期订单数据
            $orderIds = array_column($listOrder, 'id');
            $where[] = [
                function ($query) use ($orderIds) {
                    $query->whereIn('id', $orderIds);
                },
            ];
            $this->modelOrder->singleRemove($where);

            foreach ($listOrder as $order) {
                $userId = $order['user_id'];
                $this->modelUseLog->singleUpdateRaw('uuid="' . $uuid . '" and user_id=' . $userId, ['expiry_time' => time(), 'updated_at' => time()]);
            }
        }

        // 记录uuid使用记录
        $lastUserUseLog = $this->modelUserUseLog->getLastUseLogByUuid($uuid);
        $currentUserInfo = $this->modelUser->get_user($lastUserUseLog['user_id']);
        if ($currentUserInfo['user_uid'] == $uuid) {// 必须判断当前使用的UUID是否和过期的一致
            $this->modelUserUseLog->singleUpdate(['id' => $lastUserUseLog['id']], ['expiry_time' => time(), 'change_mode' => UserUseLog::CHANGE_AUTO, 'updated_at' => time()]);
            $query = $this->modelUserUseLog->getSingle(['user_id' => $lastUserUseLog['user_id']], ['old_uuid', 'user_id'], true);
            if ($query) {
                $this->modelUserUseLog->insertSingle([
                    'old_uuid' => $uuid, 'new_uuid' => $query['old_uuid'], 'user_id' => $query['user_id'],
                    'change_mode' => UserUseLog::CHANGE_AUTO, 'created_at' => time(), 'updated_at' => time()
                ]);
                $this->serviceUser->setUid($query['user_id'], $query['old_uuid']);
                $this->serviceUser->setLiang($query['user_id'], $this->modelCoolNumber->getCoolNumberType($query['old_uuid']) ? 1 : 0);
            }
        }

        // 更改靓号状态
        $this->serviceCoolNumber->stopUseUuid($uuid);
        $query = $this->modelCoolNumber->getSingleRaw('uuid="' . $uuid . '"', ['id']);
        if ($query) {
            $this->modelGoods->singleUpdate(['cool_number_id' => $query['id']], ['user_can_buy' => ShoppingMallGoods::USER_CAN_BUY_YES, 'user_can_buy_time' => 0, 'updated_at' => time()]);
        }

        DB::commit();
    }

    /**
     * 更换用户uuid(从cms管理后台)
     *
     * Created at 2021/12/9 13:18
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param string $oldUuid
     * @param string $newUuid
     * @param string $endDate
     * @param int $operatorUserId
     * @param string $operatorUser
     * @throws PublicException|\Throwable
     */
    public function changeUserUuidFromAdmin(string $oldUuid, string $newUuid, string $endDate, int $operatorUserId, string $operatorUser)
    {
        $endDate = $endDate ? strtotime($endDate) : 0;
        $user = $this->modelUser->getSingleRaw('uuid="' . $oldUuid . '"', ['user_id']);
        if (!$user) {
            throw new PublicException('用户不存在');
        }

        $checkOrder = $this->modelOrder->getTotalNumberOfQueryRaw('uuid="' . $newUuid . '" and expiry_time>' . time());
        if ($checkOrder) {// 已有人购买了该uuid
            throw new PublicException('uuid已被其他用户购买且未过期');
        }

        $checkUuid = $this->modelUser->getTotalNumberOfQueryRaw('uuid="' . $newUuid . '"');
        if ($checkUuid) {
            throw new PublicException('uuid正在被其他用户使用');
        }

        $checkCoolNumber = $this->modelCoolNumber->getTotalNumberOfQueryRaw('uuid="' . $newUuid . '" and is_use=' . CoolNumber::IS_USE_YES);
        if ($checkCoolNumber) {
            throw new PublicException('uuid已被使用');
        }

        $userId = $user['user_id'];
        DB::beginTransaction();
        try {
            $this->addUuidUseLog($userId, $newUuid, $endDate);// 添加靓号使用记录
            $this->addUuidUserUseLog($userId, $newUuid, $endDate, UserUseLog::CHANGE_BY_ADMINISTRATOR, $operatorUserId, $operatorUser);// 添加用户使用靓号记录
            $this->updateCoolNumberStatus($newUuid, $endDate);// 更新靓号使用状态
            $this->serviceUser->setUid($userId, $newUuid);// 更换用户UUID
            $this->serviceUser->setLiang($userId, $this->modelCoolNumber->getCoolNumberType($newUuid) ? 1 : 0);
            $query = $this->modelCoolNumber->getSingleRaw('uuid="' . $newUuid . '"', ['id']);
            if ($query) {
                $affectRow = $this->modelGoods->singleUpdate(['cool_number_id' => $query['id'], 'user_can_buy' => ShoppingMallGoods::USER_CAN_BUY_YES], [
                    'user_can_buy' => ShoppingMallGoods::USER_CAN_BUY_NO, 'user_can_buy_time' => $endDate,
                ]);
                if (!$affectRow) {
                    throw new PublicException('uuid已被使用');
                }
            }

            DB::commit();

            // 延时任务，处理靓号过期
            $this->serviceGoods->setDelayTaskCallback($userId, $newUuid, 0, $endDate - time());
        } catch (\Throwable $exception) {
            DB::rollBack();
            throw $exception;
        }
    }

    /**
     * 从cms后台赠送靓号
     *
     * Created at 2021/12/13 15:46
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $goodsId 靓号商品id
     * @param int $uuid 用户当前的uuid
     * @throws PublicException
     */
    public function giveCoolNumber(int $goodsId, int $uuid)
    {
        $goodsInfo = $this->modelGoods->getSingle(['id' => $goodsId], ['effective_time', 'cool_number_id', 'user_can_buy'], true);
        if (!$goodsInfo) {
            throw new PublicException('商品不存在');
        }

        if ($goodsInfo['user_can_buy'] == ShoppingMallGoods::USER_CAN_BUY_NO) {
            throw new PublicException('靓号商品不能被赠送');
        }

        $newUuid = $this->modelCoolNumber->getSingleValue(['id' => $goodsInfo['cool_number_id']], 'uuid');
        if (!$newUuid) {
            throw new PublicException('靓号不存在');
        }

        $user = $this->modelUser->getSingleRaw('uuid="' . $uuid . '"', ['user_id']);
        if (!$user) {
            throw new PublicException('用户不存在');
        }

        $checkOrder = $this->modelOrder->getTotalNumberOfQueryRaw('uuid="' . $newUuid . '" and expiry_time>' . time());
        if ($checkOrder) {// 已有人购买了该uuid
            throw new PublicException('靓号商品已被其他用户购买且未过期');
        }

        $checkUuid = $this->modelUser->getTotalNumberOfQueryRaw('uuid="' . $newUuid . '"');
        if ($checkUuid) {
            throw new PublicException('uuid正在被其他用户使用');
        }

        $checkCoolNumber = $this->modelCoolNumber->getTotalNumberOfQueryRaw('uuid="' . $newUuid . '" and is_use=' . CoolNumber::IS_USE_YES);
        if ($checkCoolNumber) {
            throw new PublicException('uuid已被使用');
        }

        DB::beginTransaction();
        $expiryTime = time() + $goodsInfo['effective_time'];// 过期时间,单位：Unix时间戳
        $orderUserId = $user['user_id'];
        $this->modelOrderLog->insertSingle(['user_id' => $orderUserId, 'goods_id' => $goodsId, 'uuid' => $newUuid,
            'expiry_time' => $expiryTime, 'giver_user_id' => 0, 'created_at' => time(), 'updated_at' => time()]);
        $where = 'user_id=' . $orderUserId . ' and uuid="' . $newUuid . '"';
        if ($this->modelOrder->getTotalNumberOfQueryRaw($where)) {// 更新时长
            $this->modelOrder->singleUpdateRaw($where, ['goods_id' => $goodsId, 'expiry_time' => $expiryTime, 'updated_at' => time(), 'is_show' => Order::IS_SHOW_YES]);
        } else {
            $orderData = ['user_id' => $orderUserId, 'goods_id' => $goodsId, 'uuid' => $newUuid,
                'expiry_time' => $expiryTime, 'created_at' => time(), 'updated_at' => time()];
            $this->modelOrder->insertSingle($orderData);// 订单数据
        }

        $affectRow = $this->modelGoods->singleUpdate(['id' => $goodsId, 'user_can_buy' => ShoppingMallGoods::USER_CAN_BUY_YES], [
            'user_can_buy' => ShoppingMallGoods::USER_CAN_BUY_NO, 'user_can_buy_time' => $expiryTime,
        ]);
        if (!$affectRow) {
            DB::rollBack();
            throw new PublicException('手慢了，靓号已被使用~');
        }

        DB::commit();

        // 延时任务，处理靓号过期
        $this->serviceGoods->setDelayTaskCallback($orderUserId, $newUuid, $goodsId, $expiryTime - time());
        $this->serviceGoods->sendMessage($orderUserId, 0, $this->modelGoods->getSingle(['id' => $goodsId], ['*'], true));
    }

    /**
     * 靓号过期提醒
     *
     * Created at 2021/12/23 20:40
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param string $uuid
     * @param int $type
     */
    public function beOverdueNotice(string $uuid, int $type)
    {
        $order = $this->modelOrder->getSingleRaw('uuid="' . $uuid . '"', ['user_id', 'expiry_time', 'goods_id']);
        if (!$order) {
            return;
        }

        if ($order['expiry_time'] <= time()) {
            return;
        }

        if (!in_array($type, [1, 2, 3])) {
            return;
        }

        $goods = $this->modelGoods->getSingle(['id' => $order['goods_id']], ['goods_name'], true);
        $msg = '您的靓号【' . $goods['goods_name'] . '】' . ($type == 1 ? '1天' : ($type == 2 ? '1个小时' : '5分钟')) . '后到期哦~';
        $this->serviceSystemMsg->sendSystemMsgToUserV2($order['user_id'], 80005, ['n' => $msg], 'kk:sys_text_msg');
    }

    /**
     * Created at 2021/12/28 17:19
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $userId
     * @return int
     */
    public function getCoolNumberExpiryTime(int $userId): int
    {
        $userInfo = $this->modelUser->get_user($userId);
        if (!$userInfo) {
            return 0;
        }

        $currentUserUuid = $userInfo['user_uid'];
        $coolNumberOrder = $this->modelOrder->getSingleRaw('user_id=' . $userId . ' and uuid="' . $currentUserUuid . '"', ['expiry_time']);
        if (!$coolNumberOrder || $coolNumberOrder['expiry_time'] <= time()) {
            return 0;
        }

        return $coolNumberOrder['expiry_time'];
    }
}